package index;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import utils.Util;

public class Term
{
    private static Map<String, Term> termMap;
    // name of this term
    private String                   name;
    // page weight (WBT) of this term in a specific document
    private Map<Document, Double>    pageWeightMap;
    // weight of this term in a specific document
    private Map<Document, Double>    weightMap;
    // total appearance of this term
    private int                      count;

    static
    {
        termMap = Collections.synchronizedMap(new HashMap<String, Term>());
    }

    public synchronized static Collection<Term> getAllTerms()
    {
        return termMap.values();
    }

    public synchronized static void clean()
    {
        termMap.clear();
    }

    public synchronized static void addTermFromInvertDocString(String lineInfo)
    {
        // Scanner scan = new Scanner(lineInfo);
        // scan.useDelimiter("[\\s|:]+");
        // String name = scan.next();
        // Term t = new Term(name);
        // while (scan.hasNext())
        // {
        // int documentID = scan.nextInt();
        // Document d = Document.getDocument(documentID);
        // d.addTerm(t);
        // double weight = scan.nextDouble();
        // t.weightMap.put(d, weight);
        // }
        String[] strs = lineInfo.split("[\\s|:]+");
        String name = strs[0];
        Term t = new Term(name);
        for (int i = 1; i < strs.length; i++)
        {
            int documentID = Integer.parseInt(strs[i]);
            Document d = Document.getDocument(documentID);
            d.addTerm(t);
            i++;
            double weight = Double.parseDouble(strs[i]);
            t.weightMap.put(d, weight);
        }
        termMap.put(name, t);
    }

    public synchronized static Term getTerm(String name)
    {
        if (termMap.containsKey(name))
            return termMap.get(name);
        Term t = new Term(name);
        termMap.put(name, t);
        return t;
    }

    private Term(String name)
    {
        this.name = name;
        this.pageWeightMap = Collections
                .synchronizedMap(new HashMap<Document, Double>());
        this.weightMap = Collections
                .synchronizedMap(new HashMap<Document, Double>());
        this.count = 0;
    }

    public void addPageWeight(double weight, Document document)
    {
        weight += pageWeightMap.containsKey(document) ? pageWeightMap
                .get(document) : 0;
        pageWeightMap.put(document, weight);
        count++;
    }

    /**
     * return the name of this term
     * 
     * @return
     */
    public String getName()
    {
        return name;
    }

    private double getPageWeight(Document document)
    {
        if (pageWeightMap.containsKey(document))
            return pageWeightMap.get(document);
        return 0;
    }

    public double getWeight(Document document)
    {
        if (weightMap.containsKey(document))
            return weightMap.get(document);

        // HTML权值
        double wbt = getPageWeight(document);
        // 网页长度权值， +0.00001 为了保证出来的值大于0
        double ds = Math.log10(Util.getMaxPageTermCount()
                / document.getTermCount() + 0.00001);
        // 出现频率权值， +0.00001 为了保证出来的值大于0
        double idf = Math.log10(1.0 * Document.getDocumentsCount()
                / this.getAppearDocumentCount() + 0.00001);
        double weight = wbt * ds * idf;
        weightMap.put(document, weight);
        return weight;
    }

    public void delete(Document d)
    {
        this.weightMap.remove(d);
        this.pageWeightMap.remove(d);
    }

    public double getWeight(int documentID)
    {
        Document d = Document.getDocument(documentID);
        return getWeight(d);
    }

    /**
     * return the number of documents which contains this term
     * 
     * @return
     */
    public int getAppearDocumentCount()
    {
        return Util.isQueryMode() ? weightMap.keySet().size() : pageWeightMap
                .keySet().size();
    }

    public Set<Document> getAllDocuments()
    {
        return weightMap.keySet();
    }

    /**
     * return the total appearances of this term in all the document
     * 
     * @return
     */
    public int getCount()
    {
        return count;
    }

    public String toString()
    {
        return String.format("[%s: documents=%d; count=%d]", name,
                getAppearDocumentCount(), count);
    }

    public String toDetailString()
    {
        StringBuilder str = new StringBuilder();
        str.append(name).append(" ");
        for (Document d : pageWeightMap.keySet())
        {
            str.append(d.getDocumentID()).append("::").append(getWeight(d))
                    .append(" ");
        }
        return str.toString();
    }
}
